#ifndef JUMENU_HEADER
#define JUMENU_HEADER
#include <atlctrlw.h>
#include <atlmisc.h>
#include <stack>

class CJuMenu : public WTL::CMenu
{
	struct MenuItemData
	{
		LPTSTR	lpstrText;
		UINT	fType;
		UINT	fState;
	};

	enum
	{
		MENUITEM_WIDTH = 120,
		MENUITEM_HEIGHT = 4 
	};

    std::stack<HMENU> m_MenuHandle;

	BOOL inited_;

protected:

	int	CreateMenuItemData(HMENU hMenu)
	{
		TCHAR	szString[100];
		BOOL	bRet = FALSE;

		CMenuHandle menu(hMenu);

		for (int i = 0; i < menu.GetMenuItemCount(); i++)
		{
#define MAX_MENU_ITEM_TEXT_LENGTH 100
			CMenuItemInfo mii;
			mii.cch = MAX_MENU_ITEM_TEXT_LENGTH;
			mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
			mii.dwTypeData = szString;
			bRet = menu.GetMenuItemInfo(i, TRUE, &mii);
			ATLASSERT(bRet);

			if (!(mii.fType & MFT_OWNERDRAW))   // not already an ownerdraw item
			{
				MenuItemData *pMI = new MenuItemData;
				ATLASSERT(pMI);
				// Make this menu item an owner-drawn
				mii.fType |= MFT_OWNERDRAW;

				pMI->fType = mii.fType;
				pMI->fState = mii.fState;
				pMI->lpstrText = new TCHAR[lstrlen(szString) + 1];
				ATLASSERT(pMI->lpstrText);
				lstrcpy( pMI->lpstrText, szString );
				mii.dwItemData = (ULONG_PTR)pMI;
				bRet = menu.SetMenuItemInfo(i, TRUE, &mii);
				ATLASSERT(bRet);
			}
		}
		m_MenuHandle.push(menu.m_hMenu);
		return 0;
	}

	int DestroyMenuItemData()
	{
		BOOL bRet = FALSE;

		//while (m_MenuHandle.Pop(&hMenu)) {
        while (!m_MenuHandle.empty()) {
			CMenuHandle menuPopup = m_MenuHandle.top();
			ATLASSERT(menuPopup.m_hMenu);
			for (int i = 0; i < menuPopup.GetMenuItemCount(); i++) {
				CMenuItemInfo mii;
				mii.fMask = MIIM_DATA | MIIM_TYPE;
				bRet = menuPopup.GetMenuItemInfo( i, TRUE, &mii );
				ATLASSERT(bRet);
				MenuItemData *pMI = (MenuItemData *)mii.dwItemData;
				if (pMI) {
					mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
					mii.fType = pMI->fType;
					mii.dwTypeData = pMI->lpstrText;
					mii.cch = lstrlen(pMI->lpstrText);
					mii.dwItemData = NULL;

					bRet = menuPopup.SetMenuItemInfo( i, TRUE, &mii );
					ATLASSERT(bRet);
					delete []pMI->lpstrText;
					delete pMI;
				}
			}
            m_MenuHandle.pop();
		}
		return 0;
	}

public:

	CJuMenu()
	{
	}

	~CJuMenu()
	{
	}

#define MENUBAR_WIDTH	24	
#define TEXTPADDING		8	

	BEGIN_MSG_MAP(CJuMenu)
		MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
		MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
		MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
		MESSAGE_HANDLER(WM_NCDESTROY, OnNcDestroy)
	END_MSG_MAP()

	void DrawItem(LPDRAWITEMSTRUCT lpDIS)
	{
		CRect rect, rect2;
		CDCHandle dc = lpDIS->hDC;
		LPRECT pRect = &lpDIS->rcItem;
		BOOL bDisabled = lpDIS->itemState & ODS_GRAYED;
		BOOL bSelected = lpDIS->itemState & ODS_SELECTED;
		BOOL bChecked = lpDIS->itemState & ODS_CHECKED;

		COLORREF clrBack = GetSysColor(COLOR_WINDOW);
		COLORREF clrNewBack = RGB(241, 241, 241);
		CBrush brBack, brBackNew;
		brBack.CreateSolidBrush(clrBack);
		brBackNew.CreateSolidBrush(clrNewBack);

		MenuItemData *pMI = (MenuItemData *)lpDIS->itemData;

		dc.SetBkMode( TRANSPARENT );

		if (pMI->fType & MFT_SEPARATOR) {
			rect.CopyRect(&lpDIS->rcItem);
			rect2.SetRect(rect.left, rect.top, rect.left + MENUBAR_WIDTH, rect.bottom);
			rect.top += rect.Height() >> 1;
			rect.left += MENUBAR_WIDTH + 2;
			dc.DrawEdge(rect, EDGE_RAISED, BF_TOP);
			dc.FillRect(rect2, brBackNew);
			CRect rcText;
			rcText.SubtractRect(&lpDIS->rcItem, rect2);
			
			CPen PenLine;
			PenLine.CreatePen(PS_SOLID, 1, RGB(226, 227, 227));
			HPEN hPen = dc.SelectPen(PenLine);
			dc.MoveTo(rcText.left, rcText.top);
			dc.LineTo(rcText.left, rcText.bottom);
			dc.SelectPen(hPen);
		}
		else {
			COLORREF clrText = GetSysColor(COLOR_MENUTEXT);
			COLORREF clrSelect = RGB(227, 238, 243);
			COLORREF clrFill = clrSelect;
			CBrush brSelect;
			CPen penBack;

			penBack.CreatePen(PS_SOLID, 0, clrBack);
			brSelect.CreateSolidBrush(clrFill);
			rect.CopyRect(&lpDIS->rcItem);
			rect2.SetRect(rect.left, rect.top, rect.left + MENUBAR_WIDTH, rect.bottom);

			CRect rcText;
			CRect rcBar;
			rcText.SubtractRect(&lpDIS->rcItem, rect2);
			rcBar.SubtractRect(&lpDIS->rcItem, rcText);

			if (bSelected) {
				HPEN hPenOld = dc.SelectPen(penBack);
				dc.FillRect(pRect, brSelect);
				dc.Draw3dRect(pRect, RGB(168, 216, 235), RGB(168, 216, 235));
				dc.SelectPen(hPenOld);

				CPen PenLine;
				PenLine.CreatePen( PS_SOLID, 1, RGB(226, 227, 227) );
				HPEN hPen = dc.SelectPen( PenLine );
				dc.MoveTo( rcText.left, rcText.top + 1 );
				dc.LineTo( rcText.left, rcText.bottom - 1 );
				dc.SelectPen( hPen );
				PenLine.DeleteObject();
				PenLine.CreatePen( PS_SOLID, 1, RGB(243, 251, 255) );
				hPen = dc.SelectPen( PenLine );
				dc.MoveTo( rcText.left + 1, rcText.top + 1 );
				dc.LineTo( rcText.left + 1, rcText.bottom - 1 );
				dc.SelectPen( hPen );
				PenLine.DeleteObject();
			}
			else
			{
			//	rect2.SetRect( rect.left, rect.top, rect.left + MENUBAR_WIDTH, rect.bottom );
				HPEN hPenOld = dc.SelectPen( penBack );
				dc.FillRect( rect, brBack );
				dc.FillRect( rect2, brBackNew );
				dc.SelectPen( hPenOld );

				dc.Draw3dRect( rect, clrBack, clrBack );
				dc.Draw3dRect( rect2, clrNewBack, clrNewBack );

				CPen PenLine;
				PenLine.CreatePen( PS_SOLID, 1, RGB(226, 227, 227) );
				HPEN hPen = dc.SelectPen( PenLine );
				dc.MoveTo( rcText.left, rcText.top );
				dc.LineTo( rcText.left, rcText.bottom );
				dc.SelectPen( hPen );
			}
			if( bDisabled )
				dc.SetTextColor( GetSysColor(COLOR_3DFACE) );
			else
				dc.SetTextColor( clrText );
			rcText.left += TEXTPADDING;
			dc.DrawText( pMI->lpstrText, lstrlen(pMI->lpstrText), rcText, DT_LEFT | DT_SINGLELINE|DT_VCENTER );
			if( bChecked )
			{
				COLORREF clrOld;
				HBITMAP hBitmap = ::LoadBitmap( NULL, MAKEINTRESOURCE(32760) );
				ATLASSERT(hBitmap);
				if( bSelected )
				{
					clrOld = dc.SetBkColor( clrFill );
				}
				else
				{
					clrOld = dc.SetBkColor( clrNewBack );
				}
				dc.DrawState( CPoint(5, 5), CSize(16, 16), hBitmap, DSS_NORMAL, (HBRUSH)NULL );
				DeleteObject( hBitmap );
				dc.SetBkColor( clrOld );
				//dc.FillSolidRect( rcBar, RGB(255, 0, 0) );
			}
		}
	}
/*
	void DrawItem(LPDRAWITEMSTRUCT lpDIS)
	{
		CRect rect, rect2;
		CDCHandle dc = lpDIS->hDC;
		LPRECT pRect = &lpDIS->rcItem;
		BOOL bDisabled = lpDIS->itemState & ODS_GRAYED;
		BOOL bSelected = lpDIS->itemState & ODS_SELECTED;
		BOOL bChecked = lpDIS->itemState & ODS_CHECKED;
		COLORREF crBackImg = CLR_NONE;

		COLORREF clrBack = GetSysColor( COLOR_WINDOW );
		COLORREF clrNewBack = GetSysColor( COLOR_3DFACE );
		CBrush brBack, brBackNew;
		brBack.CreateSolidBrush( clrBack );
		brBackNew.CreateSolidBrush( clrNewBack );

		MenuItemData *pMI = (MenuItemData *)lpDIS->itemData;

		CBrush br( ::CreateSolidBrush(RGB(189, 211, 239)) );
		dc.SetBkMode( TRANSPARENT );

		if( pMI->fType & MFT_SEPARATOR )
		{
			rect.CopyRect( &lpDIS->rcItem );
			rect2.SetRect( rect.left, rect.top, rect.left + MENUBAR_WIDTH, rect.bottom );
			rect.top += rect.Height() >> 1;
			rect.left += MENUBAR_WIDTH + 2;
			dc.DrawEdge( rect, EDGE_RAISED, BF_TOP );
			//	dc.DrawEdge( rect2, EDGE_ETCHED, BF_RECT );
			dc.FillRect( rect2, brBackNew );
			//	dc.Draw3dRect( rect, RGB(255, 0, 0), RGB(0, 0, 255));
			CRect rcText;
			rcText.SubtractRect( &lpDIS->rcItem, rect2 );
			dc.DrawEdge( rcText, EDGE_RAISED, BF_LEFT );
		}
		else
		{
			COLORREF clrText = GetSysColor( COLOR_MENUTEXT );
			COLORREF clrSelect = RGB(227, 238, 243);
			COLORREF clrFill = clrSelect;
			CBrush brSelect;
			CPen penBack;

			penBack.CreatePen( PS_SOLID, 0, clrBack );
			brSelect.CreateSolidBrush( clrFill );
			rect.CopyRect( &lpDIS->rcItem );

			rect2.SetRect( rect.left, rect.top, rect.left + MENUBAR_WIDTH, rect.bottom );

			if( bSelected )
			{
				HPEN hPenOld = dc.SelectPen( penBack );
				dc.FillRect( pRect, brSelect );
				dc.Draw3dRect( pRect, RGB(168, 216, 235), RGB(168, 216, 235));
				dc.SelectPen( hPenOld );
			}
			else
			{
				rect2.SetRect( rect.left, rect.top, rect.left + MENUBAR_WIDTH, rect.bottom );
				HPEN hPenOld = dc.SelectPen( penBack );
				dc.FillRect( rect, brBack );
				dc.FillRect( rect2, brBackNew );
				dc.SelectPen( hPenOld );

				dc.Draw3dRect( rect, clrBack, clrBack );
				dc.Draw3dRect( rect2, clrNewBack, clrNewBack );

			}
			CRect rcText;
			CRect rcBar;
			rcText.SubtractRect( &lpDIS->rcItem, rect2 );
			rcBar.SubtractRect( &lpDIS->rcItem, rcText );
			dc.DrawEdge( rcText, EDGE_RAISED, BF_LEFT );
			rcText.left += TEXTPADDING;
			dc.DrawText( pMI->lpstrText, lstrlen(pMI->lpstrText), rcText, DT_LEFT | DT_SINGLELINE|DT_VCENTER );

			if( bChecked )
			{
				dc.FillSolidRect( rcBar, RGB(255, 0, 0) );
			}
		}
	}
*/
	void MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
	{
		MenuItemData *pmd = (MenuItemData *)lpMIS->itemData;

		if (pmd->fType & MFT_SEPARATOR) {
			lpMIS->itemHeight = ::GetSystemMetrics( SM_CYMENU )/2;
			lpMIS->itemWidth = 0;
		}
		else {
			lpMIS->itemHeight = ::GetSystemMetrics(SM_CYMENU) + 2;
			lpMIS->itemWidth = MENUITEM_WIDTH;
		}
	}

	LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL &bHandled)
	{ 
		LPMEASUREITEMSTRUCT lpMIS = (LPMEASUREITEMSTRUCT)lParam;
		if( lpMIS->CtlType == ODT_MENU )
		{
			this->MeasureItem( lpMIS );
		}
		else
			bHandled = FALSE;
		return (LRESULT)TRUE;
	}

	LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL &bHandled)
	{
		LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
		if( lpDIS->CtlType == ODT_MENU )
		{
			this->DrawItem( (LPDRAWITEMSTRUCT)lParam );
		}
		else
			bHandled = FALSE;
		return (LRESULT)TRUE;
	}

	LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
	{
		if( (BOOL)HIWORD(lParam) )
		{
			bHandled = FALSE;
			return 1;
		}
		CreateMenuItemData( (HMENU)wParam );
		return 0;
	}


	LRESULT OnNcDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL &bHandled)
	{
		DestroyMenuItemData();
		/*
		This is must set to FALSE, or Assertion faile will occured!
		*/
		bHandled = FALSE;
		return 0;
	}

};

#endif